package cn.uidcc.fast.jackson;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import static cn.uidcc.fast.jackson.util.TypeUtils.*;

public class JSONObject extends JSON implements Map<String, Object> {

    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    private Map<String, Object> map;

    public JSONObject() {
        this.map = new HashMap<>(DEFAULT_INITIAL_CAPACITY);
    }

    public JSONObject(Map<String, Object> map) {
        if (map == null) {
            throw new IllegalArgumentException("map is null");
        }
        this.map = map;
    }

    public JSONObject getJSONObject(String key) {
        Object json = toJSON(get(key));
        if (json instanceof JSONObject) {
            return (JSONObject) json;
        }
        return null;
    }

    public JSONArray getJSONArray(String key) {
        Object json = toJSON(get(key));
        if (json instanceof JSONArray) {
            return (JSONArray) json;
        }
        return null;
    }

    public <T> T getObject(String key, Class<T> clazz) {
        return parseObject((toJSONString(get(key))), clazz);
    }

    public <T> T toJavaObject(Class<T> clazz) {
        if (this instanceof Map && clazz == Map.class) {
            return (T) this;
        }
        return toJavaObject(toJSONString(this), clazz);
    }


    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean containsKey(Object o) {
        return map.containsKey(o);
    }

    @Override
    public boolean containsValue(Object o) {
        return map.containsValue(o);
    }

    @Override
    public Object get(Object o) {
        Object val = map.get(o);

        if (val == null && o instanceof Number) {
            val = map.get(o.toString());
        }

        return toJSON(val);
    }

    @Override
    public Object put(String s, Object o) {
        return map.put(s, o);
    }

    @Override
    public Object remove(Object o) {
        return map.remove(o);
    }

    @Override
    public void putAll(Map<? extends String, ?> m) {
        map.putAll(m);
    }

    @Override
    public void clear() {
        map.clear();
    }

    @Override
    public Set<String> keySet() {
        return map.keySet();
    }

    @Override
    public Collection<Object> values() {
        return map.values();
    }

    @Override
    public Set<Entry<String, Object>> entrySet() {
        return map.entrySet();
    }

    /**
     * bean properties trans
     */
    public String getString(String key) {
        Object value = get(key);

        if (value == null) {
            return null;
        }

        return value.toString();
    }

    public Boolean getBoolean(String key) {
        Object value = get(key);

        if (value == null) {
            return null;
        }

        return castToBoolean(value);
    }

    public boolean getBooleanValue(String key) {
        Object value = get(key);

        Boolean booleanVal = castToBoolean(value);
        if (booleanVal == null) {
            return false;
        }
        return booleanVal.booleanValue();
    }

    public Integer getInteger(String key) {
        Object v = get(key);
        return castToInt(v);
    }

    public int getIntValue(String key) {
        Object v = get(key);

        Integer intVal = castToInt(v);
        if (intVal == null) {
            return 0;
        }
        return intVal.intValue();
    }

    public Long getLong(String key) {
        Object v= get(key);

        return castToLong(v);
    }

    public long getLongValue(String key) {
        Object v= get(key);

        Long longVal = castToLong(v);
        if (longVal == null) {
            return 0L;
        }
        return longVal.longValue();
    }

    public Float getFloat(String key) {
        Object v= get(key);

        return castToFloat(v);
    }

    public float getFloatValue(String key) {
        Object v= get(key);

        Float floatVal = castToFloat(v);
        if (floatVal == null) {
            return 0F;
        }
        return floatVal.floatValue();
    }

    public Double getDouble(String key) {
        Object v= get(key);

        return castToDouble(v);
    }

    public double getDoubleValue(String key) {
        Object v= get(key);

        Double doubleVal = castToDouble(v);
        if (doubleVal == null) {
            return 0D;
        }
        return doubleVal.doubleValue();
    }

    public BigDecimal getBigDecimal(String key) {
        Object v= get(key);

        return castToBigDecimal(v);
    }

    public BigInteger getBigInteger(String key) {
        Object v= get(key);

        return castToBigInteger(v);
    }
}
